<?php
/**
 * Created by PhpStorm.
 * User: bzg
 * Date: 2019/12/5
 * Time: 15:15
 */

namespace App\Extend\Util;

use App\Common\Exception\ServiceRunTimeException;
use App\Extend\SysExtend\Cache\Cache;
use App\Extend\SysExtend\Helper;

/**
 * 工具类
 * Class Util
 * @package App\Extend\Util
 */
class Util
{
    /**
     * 密码加密
     * @param string $pwd
     * @param string $salt
     * @return string
     * @throws \Throwable
     */
    public static function password(string $pwd, string $salt = '')
    {
        $salt = $salt ? $salt : Helper::config('extend.salt');
        return md5($pwd . $salt);
    }

    // 获取唯一ID的后缀(4位)
    private static function getUniqueIdSuffix()
    {
        // 如果是redis就用redis自增
        $cur = time();
        if(!Cache::get($cur . 'unique_id_suffix')) {
            Cache::set($cur . 'unique_id_suffix',0,2);
        }
        return Cache::inc($cur . 'unique_id_suffix') + 100 . mt_rand(1,9);
    }

    /**
     * 生成基于年月日时分秒的唯一ID
     * @return int
     */
    public static function ymdUniqueId()
    {
        return (int)date('YmdHis') . self::getUniqueIdSuffix(); // 18位
    }

    /**
     * 生成基于时间戳的唯一ID
     * @return int
     */
    public static function timeUniqueId()
    {
        return (int)time() . self::getUniqueIdSuffix(); // 14位
    }


    /**
     * 时间戳转日期
     * @param $stamp
     * @return false|string
     */
    public static function Ymd($stamp) {
        return date('Y-m-d', $stamp);
    }

    /**
     * 时间戳转日期
     * @param $stamp
     * @return false|string
     */
    public static function YmdHis($stamp) {
        return date('Y-m-d H:i:s', $stamp);
    }

    /**
     * 时间戳转日期
     * @param $stamp
     * @return false|string
     */
    public static function YmdHi($stamp) {
        return date('Y-m-d H:i', $stamp);
    }

    /**
     * 根据开始日期和结束日期获取时间戳
     * @param string $date 字符串日期
     * @param string $type start|end
     * @return false|int
     * @throws ServiceRunTimeException
     */
    public static function startEndTime($date,$type) {
        if($type == 'start') {
            $str = ' 00:00:00';
        }else{
            $str = ' 23:59:59';
        }
        try{
            return strtotime(date('Y-m-d',strtotime($date)) . $str);
        }catch (\Exception $e) {
            throw new ServiceRunTimeException('时间格式错误');
        }
    }

    /**
     * 返回当前的毫秒时间戳
     * @return float
     */
    public static function msTime() {
        list($msec, $sec) = explode(' ', microtime());
        return (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
    }

    /**
     * 计算元素的和，支持数字和数字数组
     * @param mixed ...$params
     * @return int|string
     * @throws \Exception
     */
    public static function sum(...$params)
    {
        if(count($params) <= 0) throw new \Exception('请传入正确的参数');
        $sum = 0;
        foreach ($params as $param) {
            if(is_array($param)) {
                foreach ($param as $num) {
                    if(!is_numeric($num)) throw new \Exception('请传入正确的参数');
                    $sum += $num;
                }
            }else if(is_numeric($param)) {
                $sum += $param;
            }else{
                throw new \Exception('请传入正确的参数');
            }
        }
        return $sum;
    }

    /**
     * 将字符串哈希成整型
     * @param string $string
     * @return int
     */
    public static function hash2int($string)
    {
        $hash = 0;
        $len = strlen($string);
        for($i = 0; $i < $len; $i++) {
            $hash += ($hash << 5 ) + ord($string[$i]);
        }
        return $hash % 701819;
    }

    // 产生随机字符串
    public static function randStr(int $length = 0)
    {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $str = '';
        $len = $length ? $length : mt_rand(5, 10);
        for ($i = 0; $i < $len; $i++) {
            $str .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $str;
    }

    /**
     * 转大驼峰
     * @param $str
     * @return string
     */
    public static function bigTF($str)
    {
        $str2arr = explode(' ',$str);
        $s = '';
        foreach ($str2arr as $v) {
            $s .= ucfirst($v);
        }
        return $s;
    }

    /**
     * 转小驼峰
     * @param $str
     * @return string
     */
    public static function minTF($str)
    {
        $str2arr = explode(' ',$str);
        $s = '';
        foreach ($str2arr as $k => $v) {
            if($k == 0) {
                $s .= strtolower($v);
            }else{
                $s .= ucfirst($v);
            }
        }
        return $s;
    }

    /**
     * 转下划线
     * @param $str
     * @return string
     */
    public static function botLine($str)
    {
        $str2arr = explode(' ',$str);
        $s = '';
        foreach ($str2arr as $k => $v) {
            if($k == 0) {
                $s .= strtolower($v);
            }else{
                $s .= '_'.strtolower($v);
            }
        }
        return $s;
    }

    /**
     * 计算两个坐标间的距离
     * @param $gcj02_a
     * @param $gcj02_b
     * @return float|null
     */
    public static function calcDistance($gcj02_a, $gcj02_b)
    {
        if (!is_array($gcj02_a)) {
            $gps_a = self::isGcjo2($gcj02_a);
            if (!$gps_a) {
                return null;
            }
        } else {
            $gps_a = $gcj02_a;
        }
        if (!is_array($gcj02_b)) {
            $gps_b = self::isGcjo2($gcj02_b);
            if (!$gps_b) {
                return null;
            }
        } else {
            $gps_b = $gcj02_b;
        }
        return self::nearbyDistance($gps_a[0], $gps_a[1], $gps_b[0], $gps_b[1]);
    }

    /**
     * 计算经纬度两点之间的距离
     * @param $lat1
     * @param $lon1
     * @param $lat2
     * @param $lon2
     * @return float
     */
    private static function nearbyDistance($lat1, $lon1, $lat2, $lon2)
    {
        $EARTH_RADIUS = 6372.797;
        $radLat1 = self::rad($lat1);
        $radLat2 = self::rad($lat2);
        $a = $radLat1 - $radLat2;
        $b = self::rad($lon1) - self::rad($lon2);
        $s = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2)));
        $s1 = $s * $EARTH_RADIUS;
        $s2 = round($s1, 2);
        return $s2;
    }

    /**
     * 根据经纬度和半径计算出范围
     * @param float $lat 纬度
     * @param float $lng 经度
     * @param float $radius 半径
     * @return array 范围数组
     */
    public static function calcScope($lat, $lng, $radius)
    {
        $degree = (24901 * 1609) / 360.0;
        $dpmLat = 1 / $degree;

        $radiusLat = $dpmLat * $radius;
        $minLat = $lat - $radiusLat;    // 最小纬度
        $maxLat = $lat + $radiusLat;    // 最大纬度

        $mpdLng = $degree * cos($lat * (3.1415926 / 180));
        $dpmLng = 1 / $mpdLng;
        $radiusLng = $dpmLng * $radius;
        $minLng = $lng - $radiusLng;   // 最小经度
        $maxLng = $lng + $radiusLng;   // 最大经度

        /** 返回范围数组 */
        $scope = array(
            'minLat' => $minLat,
            'maxLat' => $maxLat,
            'minLng' => $minLng,
            'maxLng' => $maxLng
        );
        return $scope;
    }

    /**
     * 地球曲率转换
     * @param $d
     * @return float
     */
    private static function rad($d)
    {
        return $d * 3.1415926535898 / 180.0;
    }
}